package com.xframe.xdal.core.util.pdf;

import com.itextpdf.text.BadElementException;
import com.itextpdf.text.DocumentException;
import com.xframe.xdal.core.util.XReflect;
import lombok.Data;
import lombok.Getter;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.chart.ui.TextAnchor;
import org.jfree.data.category.CategoryDataset;
import org.jfree.data.category.DefaultCategoryDataset;

import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * PDF折线图
 * @author xufeng
 * @version 1.0
 * @date 2022-09-26
 *
 */
@Data
public class LineChartOpt {
    /**
     * 折线图标题
     */
    private String title = "";
    /**
     * 折线图x轴名称
     */
    private String categoryAxisLabel = "X";
    /**
     * 折线图Y轴名称
     */
    private String valueAxisLabel = "Y";
    /**
     * 没有数据时的消息
     */
    private String noDataMessage = "暂无数据";
    /**
     * 折线图数据
     */
    private DefaultCategoryDataset dataset = new DefaultCategoryDataset();
    /**
     * 方向
     */
    private PlotOrientation orientation = PlotOrientation.VERTICAL;
    /**
     * 是否显示数据标题
     */
    private boolean showDataLabelFlag = false;
    /**
     * 是否显示数据点
     */
    private boolean shapesVisibleFlag = true;
    /**
     * 数据点填充的颜色
     */
    private Color fillPaintColor = Color.WHITE;

    //private Color lineColor = new Color(51, 51, 51);
    private Color lineColor = new Color(51, 51, 51);
    private Color axisColor = new Color(51, 51, 51);
    private Color tickColor = new Color(219, 218, 218);
    private Color gridlinePaint = new Color(229, 229, 229);

    private List<Color> seriesPaintList = new ArrayList<>();

    private float defaultStroke = 1.5F;

    private double top = 10;
    private double left = 10;
    private double bottom = 0;
    private double right = 10;

    //    private static final Font FONT = new Font("STSongStd-Light",
//            Font.BOLD, 12);
    private static final Font FONT = new Font("宋体",
            Font.BOLD, 12);

    private Collection<Object> values;
    private String groupName;
    private String keyName;
    private String valueName;

    private int width = 800;
    private int height = 500;



    private int rowCount = 0;

    private LineChartOpt(){
        seriesPaintList = new ArrayList<>();
        seriesPaintList.add(XLineColor.DARK_GREEN);
        seriesPaintList.add(XLineColor.LINE_YELLOW);
        seriesPaintList.add(XLineColor.LINE_BLUE);
    }

    public static LineChartOpt buildLineChartOpt(PdfBuilder pdfBuilder,String title,
                                                 String xLabel, String yLabel, Collection<Object> values,String groupName
            ,String keyName,String valueName
    ){
        LineChartOpt lineChartOpt = new LineChartOpt();
        lineChartOpt.pdfBuilder = pdfBuilder;
        lineChartOpt.categoryAxisLabel = xLabel;
        lineChartOpt.valueAxisLabel = yLabel;
        lineChartOpt.title = title;
        lineChartOpt.values = values;
        lineChartOpt.groupName = groupName;
        lineChartOpt.keyName = keyName;
        lineChartOpt.valueName = valueName;
        return lineChartOpt;
    }

    public static LineChartOpt buildLineChartOpt(String title,
                                                 String xLabel, String yLabel,
                                                 Collection<Object> values, String groupName
            , String keyName, String valueName
    ){
        LineChartOpt lineChartOpt = new LineChartOpt();
//        lineChartOpt.pdfBuilder = pdfBuilder;
        lineChartOpt.categoryAxisLabel = xLabel;
        lineChartOpt.valueAxisLabel = yLabel;
        lineChartOpt.title = title;
        lineChartOpt.values = values;
        lineChartOpt.groupName = groupName;
        lineChartOpt.keyName = keyName;
        lineChartOpt.valueName = valueName;
        return lineChartOpt;
    }

    /**
     * 宿主对象
     */
    @Getter
    private PdfBuilder pdfBuilder;


    public void buildLineChart() throws DocumentException, IOException {

        for (Object entry : this.values) {
            String groupValue = (String) XReflect.getFieldValue(entry,this.groupName);
            String keyValue = (String)XReflect.getFieldValue(entry,this.keyName);
            Number value = (Number)XReflect.getFieldValue(entry,this.valueName);
            dataset.setValue(value, groupValue, keyValue);

        }

        rowCount = dataset.getRowCount();


        //创建2D折线图,折线图分水平显示和垂直显示两种
        //legend:是否显示图例(对于简单的柱状图必须是false)
        //tooltips:是否生成工具
        //urls:是否生成URL链接
        JFreeChart chart = ChartFactory.createLineChart(this.title, this.categoryAxisLabel, this.valueAxisLabel, dataset,
                this.orientation,
                true,
                true,
                true);
        //得到绘图区

        setLineRender((CategoryPlot) chart.getPlot());
        ByteArrayOutputStream bas = new ByteArrayOutputStream();
        ChartUtils.writeChartAsJPEG(bas, 1.0f, chart, width, height, null);
        com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bas.toByteArray());
        image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
        image.scaleAbsolute(width, height);

        pdfBuilder.getDocument().add(image);
    }


    public byte[] buildLineChartImageByteArray() throws IOException {
        for (Object entry : this.values) {
            String groupValue = (String) XReflect.getFieldValue(entry,this.groupName);
            String keyValue = (String)XReflect.getFieldValue(entry,this.keyName);
            Number value = (Number)XReflect.getFieldValue(entry,this.valueName);
            dataset.setValue(value, groupValue, keyValue);

        }

        rowCount = dataset.getRowCount();


        //创建2D折线图,折线图分水平显示和垂直显示两种
        //legend:是否显示图例(对于简单的柱状图必须是false)
        //tooltips:是否生成工具
        //urls:是否生成URL链接
        JFreeChart chart = ChartFactory.createLineChart(this.title, this.categoryAxisLabel, this.valueAxisLabel, dataset,
                this.orientation,
                true,
                true,
                true);
        //得到绘图区

        setLineRender((CategoryPlot) chart.getPlot());
        ByteArrayOutputStream bas = new ByteArrayOutputStream();
        ChartUtils.writeChartAsJPEG(bas, 1.0f, chart, width, height, null);
        //new FileInputStream(imgFile)
        return bas.toByteArray();
    }


    /**
     * 设置折线图样式
     *
     * @param plot             折线图对象
     */
    private void setLineRender(CategoryPlot plot) {
        plot.setNoDataMessage(this.noDataMessage);
        plot.setInsets(new RectangleInsets(top, left, bottom, right), false);
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        renderer.setDefaultStroke(new BasicStroke(defaultStroke));
        if (showDataLabelFlag) {
            renderer.setDefaultItemLabelsVisible(true);
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING,
                    NumberFormat.getInstance()));
            renderer.setDefaultPositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER));
        }
        // 数据点绘制形状
        //显示数据点
        renderer.setDefaultShapesVisible(shapesVisibleFlag);

//        renderer.setSeriesShapesVisible(0,isShapesVisible);
        //开启填充色
        renderer.setUseFillPaint(shapesVisibleFlag);
        //数据点填充的颜色
        renderer.setSeriesFillPaint(0, fillPaintColor);
        //开启外廓线（填充色开启后有效）
        renderer.setDrawOutlines(shapesVisibleFlag);
        //使用外廓线颜色
        renderer.setUseOutlinePaint(shapesVisibleFlag);
        //设置外框线颜色
        //renderer.setSeriesOutlinePaint(0,Color.yellow);
        //设置折线的颜色
        for(int i = 0; i < rowCount; i++){
            renderer.setSeriesPaint(i, this.seriesPaintList.get(i % this.seriesPaintList.size()));
        }

        //设置外廓线大小
        renderer.setSeriesOutlineStroke(0, new BasicStroke(2.0F));
        //设置线条粗细(setDefaultStroke和这个方法冲突)
        renderer.setSeriesStroke(0, new BasicStroke(1.0F));
        //圆形数据点
//        renderer.setSeriesShape(0, new Ellipse2D.Double(-2.0D,-2.0D,5.0D,5.0D) );
        plot.setRenderer(renderer);
        setXAixs(plot, CategoryLabelPositions.UP_45);
        setYAixs(plot);
    }

    /**
     * 设置类别图表(CategoryPlot) X坐标轴线条颜色和样式
     *
     * @param plot 类别图表对象  categoryLabelPositions  x轴文字倾斜度
     */
    private void setXAixs(CategoryPlot plot, CategoryLabelPositions categoryLabelPositions) {

        CategoryAxis axis = plot.getDomainAxis();
        //categoryLabelPositions:x轴的字体倾斜度
        axis.setCategoryLabelPositions(categoryLabelPositions);
        // X坐标轴颜色
        axis.setAxisLinePaint(lineColor);
        // X坐标轴标记|竖线颜色
        axis.setTickMarkPaint(lineColor);
        axis.setLabelFont(FONT);
        axis.setTickLabelFont(FONT);
    }

    /**
     * 设置类别图表(CategoryPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
     *
     * @param plot 类别图表对象
     */
    private void setYAixs(CategoryPlot plot) {

        ValueAxis axis = plot.getRangeAxis();
        // Y坐标轴颜色
        axis.setAxisLinePaint(axisColor);
        // Y坐标轴标记|竖线颜色
        axis.setTickMarkPaint(tickColor);
        // false隐藏Y刻度
        axis.setAxisLineVisible(true);
        axis.setTickMarksVisible(true);
        // Y轴网格线条
        plot.setRangeGridlinePaint(gridlinePaint);
        plot.setRangeGridlineStroke(new BasicStroke(1));
        // 设置顶部Y坐标轴间距,防止数据无法显示
        axis.setUpperMargin(0.1);
        // 设置底部Y坐标轴间距
        axis.setLowerMargin(0.1);
        axis.setLabelFont(FONT);
        axis.setTickLabelFont(FONT);
        //设置y最小取值范围.如果数据全是0,那么0这条折线将显示在y轴中间,y轴0刻度以下将用负数表示,
        // 但是是显示的是  0E0,-1E-9,-2E-9,-3E-9,-4E-9,这样用科学计数法表示的数,加上这个可
        // 以让y轴在数据为0的时候折线在0的水平位置,接近于x轴.但是y轴刻度仍任是科学计数法.不介意的话可以用
        //还可以设置最大值,这样的话y轴刻度就不会自动生成了,就是0-1000
    /*    axis.setLowerBound(0);
        axis.setUpperBound(1000);*/

    }
}
